//
//  Line.h
//  Vector_Math
//
//  Created by John R Peterson on 3/11/12.
//  Copyright 2012 __MyCompanyName__. All rights reserved.
//

#ifndef Vector_Math_Line_h
#define Vector_Math_Line_h

#include "LinAlg.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

/*
 *  Uses covariance matricies to construct best fit lines quickly
 */
typedef struct Line_struct {
    VecList *points;   // points contained in this line
    Vec *centroid;      // centroid of the line
    Matrix *Sigma;      // covariance matrix of points on the line 
    Vec *direction;   // direction of the line the major axis
    Vec *Lambda;        // vector of eigenvalues
    short mode;         // was this line constructed using covariance of points or manually
    // TRUE indicates that it was constructed with points by the covariance method, FALSE indicates that it was manualy constructed
    
    // TODO need to get an actual line segment length, because computing the value
    // from the lambda doesn't work except when there are only 2 points in it
    // a line is not really a gaussian, need to keep track of the most extreme points or 
    // after the fact compare with the centroid
    float length;     // reflects the length of the line segment as measured from its most extreme member
    // not very probabilistically motivated
} Line;

typedef struct LineList_struct {
    Line **list;       // list of the lines contained within the list
    int size;           // how many lines does the list contain
    int maxsize;        // how many lines can the list contain
} LineList;

typedef struct PolyLine_struct {
    VecList *vertices; // all of the vertices in the line
    LineList *Llist;       // list of the lines contained within the list
    // also need to keep track of where we are on the polyline
    int pos;            // index of which line we are on so only check 3 lines total for each calculation
} PolyLine;

// Line Function prototypes
Line* Line_init(VecList *P);           // initializes with atleast 2 points
Line* Line_2Point(Vec *a, Vec *b);      // initializes with 2 points
Line* Line_createMan(Vec *centroid, Vec *direction, Vec *lambda); // initialize with the given vectors, doesn't copy those vectors!!! but will destroy them if the line is destroyed

void Line_add(Line *this, Vec *v);
void Line_addMany(Line *this, VecList *vlist);

void Line_destroy(Line *this);
void Line_destroyR(Line *this);            // destroys the line and all points it contains

Vec* Line_perpendicular(Line *this, Vec *p);
float Line_distance(Line *this, Vec *p);
float Line_distanceP(Line *this, Vec *p);

float Line_length(Line *this);              // estimates line length from the dominant eigenvalue exactly correct for 2 points

void Line_print(Line *this);

// Line List function prototypes - like array lists but not as good
void LineList_add(LineList *Llist, Line *l);             // adds the selected vector from the list
LineList* LineList_copy(LineList *that);
LineList* LineList_create(void);
LineList* LineList_createS(int initSize);               // creates an empty list with the given initial size
void LineList_destroy(LineList *Llist);                 // destroys the list without destroying the lines
void LineList_destroyR(LineList *Llist);                // destroys the list and each line
void LineList_destroyRR(LineList *llist);               // destroys the list, each line, and each point in each line
Line* L_getV(LineList *Llist, int index);                 // returns pointer to vector
short LineList_remove(LineList *Llist, int index);      // removes the vector from the selected index returns true if successful, does not destroy the removed vector
short LineList_removeR(LineList *Llist, int index);

// PolyLine Function Prototypes
PolyLine* PolyLine_init(VecList *verticies);
void PolyLine_addVertexEnd(PolyLine *this, Vec *v);
void PolyLine_destroy(PolyLine *this);              // destroys the polyline, and all of the lines it has constructed along with its vertex list, doesn't destroy the verticies that polyline was given or created with
float PolyLine_error(PolyLine *this, Vec *pos);     // computes perpendicular error to polyline
void PolyLine_removeVertexStart(PolyLine *this);    // removes vertex from the polyline, and from the associated list, destroys the line, but doesn't destroy the vertex
void PolyLine_removeVertexRStart(PolyLine *this); // destroys the underlying vertex aswell


#endif
